using System;
using System.Drawing;
using System.Collections.Generic;
using System.Drawing.Imaging;
using Clandestine.Base;
using Lime;

namespace Clandestine.Graphics
{
	/// <summary>
	/// Texture class represents a texture in GPU memory. Immutable once created.
	/// </summary>
	public abstract class Texture
	{
		internal int ReferenceCount;
		internal uint TexturePointer;	
	
		/// <summary>
		/// Whether to automatically delete the texture when not used by any Renderables.
		/// </summary>
		public bool KeepAlive { get; set; }
		public String Identifier { get; private set; }
		public bool Interpolation { get; private set; }
		public Graphics Graphics { get; private set; }
		public abstract Size Size { get; }
		
		public float[] TopLeftTexCoord = new float[2] { 0f, 0f };
		public float[] BottomRightTexCoord = new float[2] { 1f, 1f };
		
		// rly shouldnt use this unless you're FramebufferTexture/know what you're doing.
		internal Texture(Graphics graphics, string identifier, bool linearInterpolaiton, bool keepAlive = false)
		{
			this.ReferenceCount = 1;
			this.Identifier = identifier;
			this.Graphics = graphics;
			this.Interpolation = linearInterpolaiton;
			this.KeepAlive = keepAlive;
		}
		
		internal virtual void Destroy()
		{
			// Proper destroy texture, like.
			Log.i("Texture {0} destroyed.", this.Identifier);
			GL.DeleteTextures(1, new uint[] { TexturePointer });
			TexturePointer = 0;
		}
		
		public void Dispose()
		{
			Graphics.Textures.Remove(this);
		}
		
		/// <summary>
		/// Creates a new texture out of our given bitmap.
		/// </summary>
		internal void createNewGlTexture()
        {
			Graphics.BlockRendering();
			Graphics.WindowInternal.MakeContextCurrent();
			
            GL.Enable(EnableCap.Texture2D);

			uint[] ptrsgen = new uint[1];
			GL.GenTextures(1, ptrsgen);
            TexturePointer = ptrsgen[0];
			
            if (TexturePointer == 0)
                throw new Exception("The OpenGL context failed to create a new texture.");

			GL.BindTexture(TextureTarget.Texture2D, TexturePointer);
				
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.Repeat);
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.Repeat);
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) (this.Interpolation ? TextureMinFilter.Linear : TextureMinFilter.Nearest));
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) (this.Interpolation ? TextureMagFilter.Linear : TextureMagFilter.Nearest));
		
			GL.Disable(EnableCap.Texture2D);

			Graphics.WindowInternal.ReleaseContext();
			Graphics.UnblockRendering();
        }
	}
}

